home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-08-17 | 12.7 KB | 418 lines | [TEXT/MMCC] |
- Mac F2C Users:
-
- Mel Martinez spent a lot time figuring out how to add cooperative
- multi-tasking to code generated by Mac F2C. I had meant to incorporate his
- changes directly into Mac F2C, but unfortunately the deadline for the CW7
- CD pressing is here and I've been too busy with my "real" job to do it.
-
- Rather than postpone this entirely until v1.3, I've decided to include
- Mel's directions and so you can make the changes if it is important to you.
- Below is the complete set of instructions Mel sent me (which he also posted
- on c.s.m.p.*). Please note that these modifications have not been tested
- with THINK C or Symantec C.
-
- I promise to fully test (MPW, THINK, Symantec, CW) and integrate Mel's
- modifications in Mac F2C v1.3.
-
- Igor
-
-
-
-
- From mem@eta.pha.jhu.edu Fri Jul 14 10:45:35 1995
- Date: Thu, 13 Jul 1995 16:24:51 -0500
- From: Mel Martinez <mem@eta.pha.jhu.edu>
- To: Igor Mikolic-Torreira <igormt@alumni.caltech.edu>,
- mem@alumni.caltech.edu
- Newsgroups: comp.sys.mac.programmer.codewarrior,comp.sys.mac.scitech
- Subject: Multitasking with Mac F2C Fortran (improved!)
-
- Hi y'all,
-
- This posts describes how to add multitasking to Fortran code ported to the
- macintosh using Mac F2C and then MetroWerks C/C++ compiler. The idea is
- that you may have some large legacy code to run, and it would be nice to
- be able to run it in the background on your mac. For those porting
- Fortran using actual fortran compilers such as Absoft or Language Systems,
- I understand that those compilers have some options already in them for
- adding multitasking so I don't know if this is directly useful, but it
- should prove interesting. This is version 2.0 of my presentation on this
- and is greatly improved over the first.
-
- BTW: I can't say enough about how nice of a job Mac F2C seems to do
- compiling FORTRAN to C. Igor deserves a nice round of applause for his
- efforts (as well as the folks at Bell Labs).
-
- Basically, we presume you have a FORTRAN project and you can compile it C
- successfully using Mac F2C and that you will then compile and execute it
- using MetroWerk's Codewarrior compiler using one of the Mac F2C-supplied
- project stationery setups. I.E. this will be a SIOUX-based interface.
-
- The goals are: to add calls to WaitNextEvent() at the proper rate
- throughout the code. We also want the SIOUX interface to respond to user
- events like resizing the SIOUX window, updating the window in the
- background, and killing the process. For decorative purposes, we also add
- a spinning cursor. We also make use of the Time Manager to control our
- cpu SLICE time. The Time manager provide microsecond timing (within 20
- microsec) and is much more accurate than using LMGetTicks (1/60th of a
- second).
-
- Note - this code _should_ work with Think C as well, but I have not tested
- it. Also, a THINK C version needs to add an event handler as this version
- just let's SIOUX handle user events.
-
- There are two steps.
-
- On the FORTRAN side, you need to insert calls to a routine. In v1.0, I
- called it SPINCURSOR, since I was just trying to emulate the action of
- that routine under MPW C, however, To avoid confusion with the way
- SpinCursor actually behaves under Codewarrior, I now call it by what it
- does, DoMultiTask(). If you have made use of my previous version, just do
- a global replace. Basically, insert the following line anywhere in your
- fortran code you think appropriate.
-
- CALL DoMultiTask(SleepTime)
-
- Try to get it in there atleast 60 times a second, a little more than this
- will not hurt at all. Calling it 150 times a second will not hurt you
- very much, if at all. SleepTime should be a long integer. Use '1' or
- other small integer if you want a lot of cpu time, a larger number if your
- job is very leisurely. This number represents the number of ticks (1/60th
- second) that your task is willing to surrender the processor context when
- in the background before being serviced again.
-
- After this, go ahead and compile your fortran with Mac F2C.
-
- Now, we want to open up the 'main.c' file that the Mac F2C project supplies
- and add a little code. At the bottom of this post, I have appended the
- complete main.c file, so you can just grab and use that if you want to
- skip the following.
-
- First, we need to include a few things and makes some declarations. Near
- the top of the file add the following declarations:
-
- #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
- #include <CursorCtl.h> /*added 13-june-95 by M. E. Martinez*/
- #include <Events.h>
- #include <OSEvents.h>
- #include <OSUtils.h>
- #include <timer.h>
- #define SLICE 16667 /*1/60th second in microseconds*/
- EventRecord gmyEvent; /*Holds event returned by OS*/
- TMTask myTMT; /*used for Time Manager calls*/
- long delay, ohead;
- #endif /*Mac C compilers*/
-
- #ifdef __MWERKS__
- extern Boolean SIOUXQuitting;
- #endif
-
-
- If you already have some of these inclusions or declarations, be sure to
- address redundancies. Note the SLICE parameter above is the control that
- sets exactly how often the program will actually call WaitNextEvent. If
- you want to be less friendly and use more cpu time, increase this number.
- This is the recommended rate though for assuring the user interaction is
- not affected (even QuickTime movies should still run fine in the
- foreground).
-
- Next, we need to implement the following subroutine:
-
- void domultitask_(long *sleepytime)
- {
- #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
- RmvTime((QElemPtr)&myTMT); /*check the time*/
- if((delay+myTMT.tmCount - ohead)>SLICE) /*has 1/60th second gone by?*/
- {
- SpinCursor(1); /*spin the cursor*/
- if(WaitNextEvent(everyEvent, &gmyEvent, *sleepytime, NULL))
- {
- #if defined(__MWERKS__) /*This is the extent of our*/
- SIOUXHandleOneEvent(&gmyEvent); /*event handler. Add more */
- if(SIOUXQuitting)exit(EXIT_FAILURE); /*if you need to. */
- #endif
- }
- InsTime((QElemPtr)&myTMT); /*restart timer*/
- PrimeTime((QElemPtr)&myTMT,-delay);
- }
- #endif /* Macintosh C compilers */
- }
-
- Note carefully the lowercase and the underscore_ in the routine name -
- don't change this as that is how F2C translates the routine name. The
- overhead for this call, if the branch is not taken, is less than a
- millisecond (the RmvTime call is 82 microseconds) on a 66 MHz PowerMac.
- Compared to 1/60th of a second, this is tiny (less than 1 %) so you can
- afford to call this a little too often with no real impact on execution
- time.
-
-
- Finally, we have one small edit left. We need to initialize our Time
- Manager entry. Just after the program starts, a little after the main()
- call, but well before the MAIN() call that starts the FORTRAN code, put:
-
- #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
- /* MEM 13-july-95 for doMultiTask() */
- InitCursorCtl(nil); /* initialize timer for doMultiTask() */
- memset((void *)&myTMT, 0, sizeof(TMTask));
- delay = 100*1000000;
- InsTime((QElemPtr)&myTMT);
- PrimeTime((QElemPtr)&myTMT,-delay);
- #endif /* Macintosh C compilers */
-
- That's it! Play with the SleepTime and SLICE parameters if you want, to
- see how they affect the cpu usage of your code, though the default SLICE
- value seems to work well. I tend to set SleepTime to '1' myself and
- everything just hums along. TaskIt! indicates that my app gets the vast
- majority of the cpu time in the background, even with about 12 other
- applications loaded, yet I feel no degradation in user responsiveness.
-
- I welcome suggestions for improvements/corrections. One possibility is
- passing both the SLICE and SleepTime parameters with the DoMultiTask()
- call, but I wanted to keep the implementation simple on the FORTRAN side
- (don't want to have to remember which parameter does what, since they take
- very different values).
-
- I hope this is helpful.
-
- Cheers,
-
- Mel Martinez
- The Johns Hopkins University
- Dept. of Physics
- mem@jhu.edu
-
-
- /*===================main.c=============================*/
-
- /* STARTUP PROCEDURE FOR UNIX FORTRAN PROGRAMS */
-
- #include "stdio.h"
- #include "signal.h"
-
- #ifndef SIGIOT
- #ifdef SIGABRT
- #define SIGIOT SIGABRT
- #endif
- #endif
-
- #if defined(THINK_C) || defined(THINK_CPLUS)
- #include <console.h> /* IMT 2 Dec 94 Needed to make command line work
- under THINK */
- #endif
-
- #ifdef __MWERKS__ /* IMT 2 Dec 94 Needed for MetroWerks (from Dirk
- Froehling) */
- #include <SIOUX.h>
- #endif
-
- #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
- #include <CursorCtl.h> /*added 13-june-95 by M. E. Martinez*/
- #include <Events.h>
- #include <OSEvents.h>
- #include <OSUtils.h>
- #include <timer.h>
- #define SLICE 16667 /*1/60th second in microseconds*/
- EventRecord gmyEvent; /*Holds event returned by OS*/
- TMTask myTMT; /*used for Time Manager calls*/
- long delay, ohead;
- #endif /*Mac C compilers*/
-
- #ifdef __MWERKS__
- extern Boolean SIOUXQuitting;
- #endif
-
-
-
-
- #ifndef KR_headers
- #include "stdlib.h"
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- #ifdef NO__STDC
- #define ONEXIT onexit
- extern void f_exit();
- #else
- #ifndef KR_headers
- extern void f_exit(void);
- #ifndef NO_ONEXIT
- #define ONEXIT atexit
- extern int atexit(void (*)(void));
- #endif
- #else
- #ifndef NO_ONEXIT
- #define ONEXIT onexit
- extern void f_exit();
- #endif
- #endif
- #endif
-
- #ifdef KR_headers
- extern void f_init(), sig_die();
- extern int MAIN__();
- #define Int /* int */
- #else
- extern void f_init(void), sig_die(char*, int);
- extern int MAIN__(void);
- #define Int int
- #endif
-
- static void sigfdie(Int n)
- {
- sig_die("Floating Exception", 1);
- }
-
-
- static void sigidie(Int n)
- {
- sig_die("IOT Trap", 1);
- }
-
- #ifdef SIGQUIT
- static void sigqdie(Int n)
- {
- sig_die("Quit signal", 1);
- }
- #endif
-
-
- static void sigindie(Int n)
- {
- sig_die("Interrupt", 0);
- }
-
- static void sigtdie(Int n)
- {
- sig_die("Killed", 0);
- }
-
- #ifdef SIGTRAP
- static void sigtrdie(Int n)
- {
- sig_die("Trace trap", 1);
- }
- #endif
-
-
- /* The following function written by Dirk Froehling; modified by IMT */
-
- #if defined(THINK_C) || defined(THINK_CPLUS)
-
- #include <Files.h>
- #include <Processes.h>
-
-
- static void SetDefVolToAppVol(void)
- {
- ProcessSerialNumber currentPSN;
- ProcessInfoRec info;
- FSSpec appSpec;
-
- OSErr err;
-
- currentPSN.highLongOfPSN = 0;
- currentPSN.lowLongOfPSN = kCurrentProcess;
- info.processInfoLength = sizeof(ProcessInfoRec);
- info.processName = NULL;
- info.processAppSpec = &appSpec;
- err = GetProcessInformation(¤tPSN, &info);
- err = HSetVol(NULL, appSpec.vRefNum, appSpec.parID);
- }
-
- #endif
-
- /*the following by MEM 13-july-95 for DoMultiTask() from FORTRAN (w/f2c) */
- /* Now we add some cooperative multi-tasking here!*/
-
- void domultitask_(long *sleepytime)
- {
- #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
- RmvTime((QElemPtr)&myTMT); /*check the time*/
- if((delay+myTMT.tmCount - ohead)>SLICE) /*has 1/60th second gone by?*/
- {
- SpinCursor(1); /*spin the cursor*/
- if(WaitNextEvent(everyEvent, &gmyEvent, *sleepytime, NULL))
- {
- #if defined(__MWERKS__) /*This is the extent of our*/
- SIOUXHandleOneEvent(&gmyEvent); /*event handler. Add more */
- if(SIOUXQuitting)exit(EXIT_FAILURE); /*if you need to. */
- #endif
- }
- InsTime((QElemPtr)&myTMT); /*restart timer*/
- PrimeTime((QElemPtr)&myTMT,-delay);
- }
- #endif /* Macintosh C compilers */
- }
-
- int xargc;
- char **xargv;
-
-
- #ifdef KR_headers
- main(argc, argv) int argc; char **argv;
- #else
- main(int argc, char **argv)
- #endif
- {
-
- #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
-
- argc = ccommand( &argv ); /* IMT 2 Dec 94 Think/Codewarrior mod */
- InitCursorCtl(nil); /* MEM 13-july-95 for doMultiTask() */
- /* initialize timer for doMultiTask() */
- memset((void *)&myTMT, 0, sizeof(TMTask));
- delay = 100*1000000;
- InsTime((QElemPtr)&myTMT);
- PrimeTime((QElemPtr)&myTMT,-delay);
-
- #endif /* Macintosh C compilers */
-
- #if defined(THINK_C) || defined(THINK_CPLUS)
-
- SetDefVolToAppVol(); /* IMT 14 Dec 94 Thanks to Dirk Froehling */
-
- #endif /* Macintosh C compilers */
-
- xargc = argc;
- xargv = argv;
- signal(SIGFPE, sigfdie); /* ignore underflow, enable overflow */
- #ifdef SIGIOT
- signal(SIGIOT, sigidie);
- #endif
- #ifdef SIGTRAP
- signal(SIGTRAP, sigtrdie);
- #endif
- #ifdef SIGQUIT
- if(signal(SIGQUIT,sigqdie) == SIG_IGN)
- signal(SIGQUIT, SIG_IGN);
- #endif
- if(signal(SIGINT, sigindie) == SIG_IGN)
- signal(SIGINT, SIG_IGN);
- signal(SIGTERM,sigtdie);
-
- #ifdef pdp11
- ldfps(01200); /* detect overflow as an exception */
- #endif
-
- f_init();
- #ifndef NO_ONEXIT
- ONEXIT(f_exit);
- #endif
-
- /*call the FORTRAN 'MAIN' program now*/
- MAIN__();
-
- #ifdef NO_ONEXIT
- f_exit();
- #endif
- exit(0); /* exit(0) rather than return(0) to bypass Cray bug */
- return 0; /* For compilers that complain of missing return values; */
- /* others will complain that this is unreachable code. */
- }
- #ifdef __cplusplus
- }
- #endif
-